/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// sg_mover.cpp - moveable entities
//


#include "sg_local.h"


enum moverFlags_t {
	MOVER_NO_PUSH					= BIT(0),
	MOVER_NO_USE					= BIT(1),
	MOVER_NO_TOUCH					= BIT(2),
	MOVER_NO_REVERSE				= BIT(3),
	MOVER_NO_STOP					= BIT(4),
	MOVER_TOGGLE					= BIT(5),
	MOVER_CONTINUOUS				= BIT(6),
	MOVER_REVERSE_TRIGGER			= BIT(7),
	MOVER_X_AXIS					= BIT(8),
	MOVER_Y_AXIS					= BIT(9),
	MOVER_ROTATE					= BIT(10),
	MOVER_FACE_DIRECTION			= BIT(11),
	MOVER_STOP_AT_END				= BIT(12),
};


/*
 ==================
 
 ==================
*/
static void SG_BinaryMover_Init (etEntity *entity, const glqVec3 &origin1, const glqVec3 &origin2, const glqAngles &angles1, const glqAngles &angles2, bool reverse){

	mover_t		*mover = (mover_t *)entity->state.buffer;
	etEntity	*check;
	const char	*team;
	float		time;
	int			duration;

	if (reverse)
		entity->moverState = MOVER_POS2;
	else
		entity->moverState = MOVER_POS1;

	entity->moverOrigin1 = origin1;
	entity->moverOrigin2 = origin2;

	entity->moverAngles1 = angles1;
	entity->moverAngles2 = angles2;

	if (entity->spawnDict.GetFloat("time", &time))
		duration = SEC2MS(time);
	else {
		// Calculate time to reach the other position from speed
		if (!(entity->spawnFlags & MOVER_ROTATE))
			time = (origin2 - origin1).Length() * 1000.0f / entity->speed;
		else {
			if (entity->spawnFlags & MOVER_X_AXIS)
				time = (angles2[2] - angles1[2]) * 1000.0f / entity->speed;
			else if (entity->spawnFlags & MOVER_Y_AXIS)
				time = (angles2[0] - angles1[0]) * 1000.0f / entity->speed;
			else
				time = (angles2[1] - angles1[1]) * 1000.0f / entity->speed;
		}

		duration = glqMath::FloatToInt(time);
	}

	if (duration < 1)
		duration = 1;

	// Set time and duration
	entity->time = level.time;
	entity->duration = duration;

	// Set initial activator
	entity->activator = entity;

	// Set initial position and orientation
	if (reverse){
		entity->SetOrigin(origin2);
		entity->SetAngles(angles2);
	}
	else {
		entity->SetOrigin(origin1);
		entity->SetAngles(angles1);
	}
}


/*
 ==============================================================================

 FUNC_DOOR

 ==============================================================================
*/


/*
 ==================
 
 NOTE: we need to make sure we don't just set default values but get the "real" values from
 the etDict
 ==================
*/
void SG_FuncDoor_Spawn (etEntity *self){

	mover_t		*mover = (mover_t *)self->state.buffer;
	glqVec3		dir, absDir;
	glqVec3		offset;
	float		lip, angle;

	// Parse the spawn parameters that will be transmitted to clients
	self->ParseMoverState();

	// Get the flags

	// Get the wait time
	self->wait = self->spawnDict.GetFloat("wait", "3");

	// Get the damage
	self->damage = self->spawnDict.GetInteger("dmg", "2");
	self->damage = Max(self->damage, 0);

	// Get the speed
	self->speed = self->spawnDict.GetFloat("speed", "400");
	self->speed = Max(self->speed, 0.001f);

	// Get the audible range
	self->audibleRange = self->spawnDict.GetFloat("audibleRange", "2500");
	self->audibleRange = Max(self->audibleRange, 0.0f);

	// Get the sound shaders

	// Finish setting up
	if (mover->model)
		self->flags |= FL_VISIBLE;

	// Set mover type
	self->moverType = MOVER_BINARY;

	// Set the clip model
	glqBounds bounds;

	bounds.Set(-8.0f, -8.0f, 0.0f, 8.0f, 8.0f, 16.0f);

	self->SetClipModel(NULL, 0, bounds);

	// Enable physics
	self->EnablePhysics();

	// Set the callback functions

	// Initialize the binary mover
	if (self->spawnFlags & MOVER_ROTATE){

	}
	else {
		lip = self->spawnDict.GetFloat("lip", "8");

		// FIXME: i think this calculation is wrong, thats why the inlineModel isn't in it's place

		if (!self->spawnDict.GetFloat("angle", &angle))
			dir.Set(1.0f, 0.0f, 0.0f);
		else
			SG_AngleToDir(angle, dir);

		absDir.x = glqMath::FAbs(dir.x);
		absDir.y = glqMath::FAbs(dir.y);
		absDir.z = glqMath::FAbs(dir.z);

		offset = dir * (absDir.Dot(self->absBounds[1] - self->absBounds[0]) - lip);

		SG_BinaryMover_Init(self, self->GetOrigin(), self->GetOrigin() + offset, self->GetAngles(), self->GetAngles(), self->spawnDict.GetBool("startOpen"));
	}
}

/*
 ==============================================================================

 FUNC_DOOR_SECRET

 ==============================================================================
*/


/*
 ==================
 
 ==================
*/
void SG_FuncDoorSecret_Spawn (etEntity *self){

}